/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 main.c
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Forrest Yu, 2005
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "video.h"
#include "windows.h"

/*======================================================================*
 kernel_main
 *======================================================================*/
PUBLIC int kernel_main() {
	disp_str("-----\"kernel_main\" begins-----\n");
	disp_str("testmsg\n");
	/* Initialization of Number of Windows */
	NumOfWin = 0;

	TASK* p_task = task_table;
	PROCESS* p_proc = proc_table;
	char* p_task_stack = task_stack + STACK_SIZE_TOTAL;
	u16 selector_ldt = SELECTOR_LDT_FIRST;
	int i, j, tempIndex;
	u8 privilege;
	u8 rpl;
	int eflags;
	for (i = 0; i < NR_TASKS + NR_PROCS; i++) {
		if (i < NR_TASKS) { /* 任务 */
			p_task = task_table + i;
			privilege = PRIVILEGE_TASK;
			rpl = RPL_TASK;
			eflags = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
		} else { /* 用户进程 */
			p_task = user_proc_table + (i - NR_TASKS);
			privilege = PRIVILEGE_USER;
			rpl = RPL_USER;
			eflags = 0x202; /* IF=1, bit 2 is always 1 */
		}

		strcpy(p_proc->p_name, p_task->name); // name of the process
		p_proc->pid = i; // pid

		p_proc->ldt_sel = selector_ldt;

		memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
				sizeof(DESCRIPTOR));
		p_proc->ldts[0].attr1 = DA_C | privilege << 5;
		memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
				sizeof(DESCRIPTOR));
		p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
		p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;

		p_proc->regs.eip = (u32) p_task->initial_eip;
		p_proc->regs.esp = (u32) p_task_stack;
		p_proc->regs.eflags = eflags;

		p_proc->nr_tty = 0;

		p_task_stack -= p_task->stacksize;
		p_proc++;
		p_task++;
		selector_ldt += 1 << 3;
	}

	proc_table[0].ticks = proc_table[0].priority = 10;
	proc_table[1].ticks = proc_table[1].priority = 5;
	proc_table[2].ticks = proc_table[2].priority = 5;
	proc_table[3].ticks = proc_table[3].priority = 5;
	proc_table[4].ticks = proc_table[4].priority = 5;

	proc_table[1].nr_tty = 0;
	proc_table[2].nr_tty = 1;
	proc_table[3].nr_tty = 1;
	proc_table[4].nr_tty = 1;

	k_reenter = 0;
	ticks = 0;

	p_proc_ready = proc_table;

//	vtest();
//	video_test();
//	init_mouse();
	init_clock();
	//init_keyboard();
	//old_picture = ( unsigned short * )0x500;
	unsigned short color = vesa_compond_rgb(63, 63, 63);
	vesa_draw_point(200, 200, color);
	for (i = 0; i < 320; i++) {
		for (j = 0; j < 200; j++) {
			vesa_draw_point(i, j, 0);
		}
	}
	//vesa_paint_string("000000",200,150,80,6);
	//vesa_draw_rect(10,10,60,60,50);
	/*
	 for(i=0;i<26;i++)
	 {
	 vesa_paint_letter('A'+i,10+7*i,100,80);
	 }
	 for(i=0;i<10;i++)
	 {
	 vesa_paint_number(i,10+7*i,150,80);
	 }
	 vesa_paint_string("LAOPEI",310,150,80,6);
	 */
	/*
	 unsigned short _V[4][8] = {	{1,1,1,1,1,1,1,1},
	 {0,0,0,0,0,0,0,0},
	 {0,0,0,0,0,0,0,0},
	 {0,0,0,0,0,0,0,0}};
	 unsigned short old_color = 0;
	 PUBLIC unsigned short V[4][8];
	 for (i = 0; i < 4; i++){
	 for (j = 0; j < 8; j ++){
	 if (_V[i][j] == 1) V[i][j] = color;
	 else V[i][j] = old_color;
	 vesa_draw_point(100 + j,100 + i,V[i][j]);
	 }
	 }*/

	//vesa_paint_matrix (V, 120, 120, 4, 8);
	//vesa_clean_screen(color);
	restart();

	while (1) {
	}
}
int tempLabel = 0;
/*======================================================================*
 TestA
 *======================================================================*/
void TestA() {
	struct Message temp;
	int i = 0, NotNullMsg;
	while (1) {
		//video_test();
		//for (i = 0; i < 100; i++)  vesa_draw_point(i,i,color);
		//printf("<Ticks:%x>", get_ticks());

		// Repaint Windows
		for (i = 0; i < NumOfWin; i++) {
			if (WinRegister[i].Visible == 1 && WinRegister[i].Alive == 1)
				PaintWin(i);
		}

		// Decorating the Top Message
		// Decide to whom the message will be assigned
		NotNullMsg = LookTopMessage(&SysMessages, &temp);
		if (NotNullMsg) {
			temp.BelongsTo = GetWinByXY(temp.MouseX, temp.MouseY);
		}

		// If the message doesn't belong to any window, simpy consume it.
		// To be improved later (a more comprehensive mechanism is to be introduced)
		if (temp.BelongsTo == -1)
			NotNullMsg = GetMessage(&SysMessages, &temp);
		else
			SetTopMessage(&SysMessages, temp); //Send the decoration signal
		milli_delay(200);
	}
}

/*======================================================================*
 TestB
 *======================================================================*/
void TestB() {
	int i = 0x1000;
	int MyWin, NotNullMsg;
	int MyClose, MyMaximize, MyMinimize, MyTaskItem;
	int MyLabel;
	int TaskBar;
	int delay = 0;
	struct Message Consumption;

	TaskBar = RegWin(1, 190, 7, 315, 4, ROOT_WIN, 0, "");
	MyWin = RegWin(10, 10, 100, 150, 0, ROOT_WIN, 1, ""); //Register the main window for this process
	WinRegister[MyWin].Visible = 0;

	//vesa_paint_string("LAOPEI",WinRegister[MyWin].x+20,WinRegister[MyWin].y+1,80,6);
	MyClose = RegWin(WinRegister[MyWin].x, WinRegister[MyWin].y, 7, 7, 1, MyWin,
			0, "");
	MyMaximize = RegWin(WinRegister[MyWin].x + 7, WinRegister[MyWin].y, 7, 7, 2,
			MyWin, 0, "");
	MyMinimize = RegWin(WinRegister[MyWin].x + 14, WinRegister[MyWin].y, 7, 7,
			3, MyWin, 0, "");
	MyTaskItem = RegWin(60, 192, 8, 100, 5, MyWin, 0, "");
	MyLabel = RegWin(WinRegister[MyWin].x + 5, WinRegister[MyWin].y + 20, 6, 42,
			6, MyWin, 0, "WINDOW0");
	tempLabel = MyLabel;

	//Hide the windows at first
	for (i = 0; i < NumOfWin; i++) {
		if (WinRegister[i].Father == MyWin && WinRegister[i].Type != 5)
			WinRegister[i].Visible = 0;
	}

	/* Message Loop */
	delay = 0;
	while (1) {
		// Waiting for messages sent to me

		while (ToWait(MyWin) && ToWait(MyClose) && ToWait(MyMaximize)
				&& ToWait(MyMinimize) && ToWait(MyTaskItem)) {
			delay++;
			if (delay == 3999) {
				if (WinRegister[MyWin].Alive && WinRegister[MyWin].Visible) {
					if (WinRegister[MyLabel].HaveLabel == 0) {
						WinRegister[MyLabel].HaveLabel = 1;
						ChangeLabel(MyLabel, "HELLO");
					} else {
						WinRegister[MyLabel].HaveLabel = 0;
						ChangeLabel(MyLabel, "WORLD");
					}
				}
				delay = 0;
			}
		}
		NotNullMsg = GetMessage(&SysMessages, &Consumption); // Consume it

		/* Do something according to the message */
		if (Consumption.LeftButtonDown && Consumption.BelongsTo == MyWin) {
			//Resize(MyWin,WinRegister[MyWin].Height+1,WinRegister[MyWin].Width+1);

		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyClose) {
			WinRegister[MyWin].Alive = 0;
			WinRegister[MyClose].Alive = 0;
			WinRegister[MyMaximize].Alive = 0;
			WinRegister[MyMinimize].Alive = 0;
			WinRegister[MyTaskItem].Alive = 0;
			WinRegister[MyLabel].Alive = 0;

			EraseWin(MyWin);

			WinRegister[MyWin].Height = 0;
			WinRegister[MyWin].Width = 0;
			WinRegister[MyWin].x = 600;
			WinRegister[MyWin].y = 600;

		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyMaximize) {
			Maximize(MyWin);
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyMinimize) {
			Minimize(MyWin);
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyTaskItem) {
			Minimize(MyWin);
		}

		milli_delay(200);
	}
}

/*======================================================================*
 TestC
 *======================================================================*/
void TestC() {
	int i = 0x2000;
	int MyWin, NotNullMsg;
	int MyClose, MyMaximize, MyMinimize, MyTaskItem;
	int MyLabel;
	int delay = 0;
	struct Message Consumption;
	MyWin = RegWin(100, 40, 100, 150, 0, ROOT_WIN, 1, " ");
	WinRegister[MyWin].Visible = 0;

	MyClose = RegWin(WinRegister[MyWin].x, WinRegister[MyWin].y, 7, 7, 1, MyWin,
			0, " ");
	MyMaximize = RegWin(WinRegister[MyWin].x + 7, WinRegister[MyWin].y, 7, 7, 2,
			MyWin, 0, " ");
	MyMinimize = RegWin(WinRegister[MyWin].x + 14, WinRegister[MyWin].y, 7, 7,
			3, MyWin, 0, " ");
	MyTaskItem = RegWin(170, 192, 8, 100, 5, MyWin, 0, " ");
	MyLabel = RegWin(WinRegister[MyWin].x + 5, WinRegister[MyWin].y + 20, 6, 42,
			6, MyWin, 0, "WINDOW1");

	//Hide the windows at first	
	for (i = 0; i < NumOfWin; i++) {
		if (WinRegister[i].Father == MyWin && WinRegister[i].Type != 5)
			WinRegister[i].Visible = 0;
	}

	delay = 0;
	while (1) {
		// Waiting for messages sent to me

		while (ToWait(MyWin) && ToWait(MyClose) && ToWait(MyMaximize)
				&& ToWait(MyMinimize) && ToWait(MyTaskItem)) {
			delay++;
			if (delay == 3999) {
				if (WinRegister[MyWin].Alive && WinRegister[MyWin].Visible) {
					if (WinRegister[MyLabel].HaveLabel == 0) {
						WinRegister[MyLabel].HaveLabel = 1;
						ChangeLabel(MyLabel, "HELLO");
					} else {
						WinRegister[MyLabel].HaveLabel = 0;
						ChangeLabel(MyLabel, "WORLD");
					}
				}
				delay = 0;
			}
		}
		NotNullMsg = GetMessage(&SysMessages, &Consumption); // Consume it

		/* Do something according to the message */
		if (Consumption.LeftButtonDown && Consumption.BelongsTo == MyWin) {
			//Resize(MyWin,WinRegister[MyWin].Height+1,WinRegister[MyWin].Width+1);
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyClose) {
			WinRegister[MyWin].Alive = 0;
			WinRegister[MyClose].Alive = 0;
			WinRegister[MyMaximize].Alive = 0;
			WinRegister[MyMinimize].Alive = 0;
			WinRegister[MyTaskItem].Alive = 0;
			WinRegister[MyLabel].Alive = 0;

			EraseWin(MyWin);

			WinRegister[MyWin].Height = 0;
			WinRegister[MyWin].Width = 0;
			WinRegister[MyWin].x = 600;
			WinRegister[MyWin].y = 600;
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyMaximize) {
			Maximize(MyWin);
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyMinimize) {
			WinRegister[MyWin].Visible = 0;
			WinRegister[MyClose].Visible = 0;
			WinRegister[MyMaximize].Visible = 0;
			WinRegister[MyMinimize].Visible = 0;
			WinRegister[MyLabel].Visible = 0;
			EraseWin(MyWin);
		} else if (Consumption.LeftButtonDown
				&& Consumption.BelongsTo == MyTaskItem) {
			if (WinRegister[MyWin].Visible == 1) {
				WinRegister[MyWin].Visible = 0;
				WinRegister[MyClose].Visible = 0;
				WinRegister[MyMaximize].Visible = 0;
				WinRegister[MyMinimize].Visible = 0;
				WinRegister[MyLabel].Visible = 0;
				EraseWin(MyWin);

			} else {
				WinRegister[MyWin].Visible = 1;
				WinRegister[MyClose].Visible = 1;
				WinRegister[MyMaximize].Visible = 1;
				WinRegister[MyMinimize].Visible = 1;
				WinRegister[MyLabel].Visible = 1;
			}
		}
		milli_delay(200);
	}

}

/*======================================================================*
 TestD
 *======================================================================*/
void TestD() {
	int i = 0x3000;
	while (1) {
	}
	/*
	 int MyWin, NotNullMsg;
	 struct Message Consumption;

	 int j=0;

	 while(1){
	 while(ToWait(MyWin)){};
	 NotNullMsg = GetMessage(&SysMessages, &Consumption);
	 //if (Consumption.LeftButtonDown) Resize(MyWin,WinRegister[MyWin].Height+1,WinRegister[MyWin].Width+1);
	 milli_delay(200);
	 }
	 */
}
